package src.base;

import src.loadbalancer.*;

import java.awt.EventQueue;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import java.util.Properties;
import java.util.Scanner;
import java.util.Vector;

public class Simulator {

	
	//Config file
	public static final String CONFIG_FILE = "trunk/config";
	public static Properties prop;
	
	//Gauss and Exp
	public Gauss gauss;
	public Exponentiel exp;
	
	//Source
	public Source source_1;
	public Source source_2;
	public Source source_3;
	public Source source_4;
	public Source source_5;
	
	//LoadBalancer
	public LoadBalancer1 lb_1;
	public LoadBalancer2 lb_2;
	public LoadBalancer3 lb_3;
	public LoadBalancer4 lb_4;
	public LoadBalancer5 lb_5;
	public LoadBalancer6 lb_6;
	public LoadBalancer7 lb_7;
	public LoadBalancer8 lb_8;
	
	//Scanner
	public Scanner sc;
	
	//User interface
	public int state = 0;
	public int nb_state = 2;

	

	/**
	 * Launch the application.
	 */
	public static void main(String[] args) {
		EventQueue.invokeLater(new Runnable() {
			@Override
			public void run() {
				try {
					Simulator simulator = new Simulator();
					
					System.out.println("-- Start --");

					//Initialisation
					int clock = 0;
					int gauss_number = 0;
					int exp_number = 0;
					List<Element> listout = new Vector<Element>();
					
					simulator.printStatus(simulator.lb_2, gauss_number, exp_number);
					
					String s = "";
					while(s.compareTo("quit") != 0)
					{						
						//Wait the user to go on
						System.out.println("PUSH -- Please hit 'Enter' or type 'quit' to exit");
						s = simulator.sc.nextLine();
					
						//Push
						gauss_number = simulator.gauss.nextInt();
						simulator.lb_2.push(simulator.source_1, gauss_number);
						simulator.source_1.moveIndexOf(gauss_number);
						simulator.printStatus(simulator.lb_2, gauss_number, exp_number);
						
						//Wait the user to go on
						System.out.println("PULL -- Please hit 'Enter' or type 'quit' to exit");
						s = simulator.sc.nextLine();
						
						//Pull						
						exp_number = simulator.exp.nextInt();
						listout = simulator.lb_2.pull(exp_number);
						simulator.printStatus(simulator.lb_2, gauss_number, listout.size());					

						//Wait the user to go on
						System.out.println("DISPATCH -- Please hit 'Enter' or type 'quit' to exit");
						s = simulator.sc.nextLine();
						
						//Dispatch
						simulator.lb_2.dispatch(listout);
						simulator.printStatus(simulator.lb_2, gauss_number, listout.size());
						
						
						//clock
						System.out.println("clock ("+ ++clock +")");
						
						gauss_number = 0;
						exp_number = 0;
					}
					//End of the application
					System.out.println("END");
					System.exit(0);
					
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		});
	}

	/**
	 * Create the application.
	 */
	public Simulator() 
	{
		initialize();	
	}

	/**
	 * Initialize the Simulator
	 */
	private void initialize() {
		
		//Load config file to be access in the entire application
		loadConfig();
		
		//Create all different LoadBalancer
		int nb_server = getProperty("app.number_of_server");
		lb_1 = new LoadBalancer1(nb_server);
		lb_2 = new LoadBalancer2(nb_server);
		lb_3 = new LoadBalancer3(nb_server);
		lb_4 = new LoadBalancer4(nb_server);
		lb_5 = new LoadBalancer5(nb_server);
		lb_6 = new LoadBalancer6(nb_server);
		lb_7 = new LoadBalancer7(nb_server);
		lb_8 = new LoadBalancer8(nb_server);
		
		//Create 5 different source file
		source_1 = 
			new Source	(
					getProperty("app.generator_source_1.seed"), 
					getProperty("app.generator_source.range"),
					getProperty("app.generator_source.sample")
				);
		
		source_2 = 
			new Source	(
					getProperty("app.generator_source_2.seed"), 
					getProperty("app.generator_source.range"),
					getProperty("app.generator_source.sample")
				);
		
		source_3 = 
			new Source	(
					getProperty("app.generator_source_3.seed"), 
					getProperty("app.generator_source.range"),
					getProperty("app.generator_source.sample")
				);
		
		source_4 = 
			new Source	(
					getProperty("app.generator_source_4.seed"), 
					getProperty("app.generator_source.range"),
					getProperty("app.generator_source.sample")
				);
		
		source_5 = 
			new Source	(
					getProperty("app.generator_source_5.seed"), 
					getProperty("app.generator_source.range"),
					getProperty("app.generator_source.sample")
				);
		
		//Create the generator Gauss and Exp
		gauss = new Gauss(
				getProperty("app.gauss.seed.x"), 
				getProperty("app.gauss.seed.y"), 
				getProperty("app.gauss.m"), 
				getProperty("app.gauss.e"));
		
		exp = new Exponentiel(
				getProperty("app.exp.seed.x"), 
				getProperty("app.exp.seed.y"), 
				getProperty("app.exp.m"), 
				getProperty("app.exp.e"));
				
		//Scanner
		sc = new Scanner(System.in);
	}

	public void loadConfig()
	{
		try {
			Simulator.prop = new Properties();
			InputStream is = new FileInputStream(CONFIG_FILE);			
			Simulator.prop.load(is);
		} catch (FileNotFoundException e) {
			System.err.println("Configuration file not found !");
		} catch (IOException e) {
			e.printStackTrace();
		}
	}	
	
	public static int getProperty(String name)
	{
		return Integer.parseInt(prop.getProperty(name));
	}

	public void incState()
	{
		state = (state + 1) % nb_state;
	}
	
	public void printStatus(LoadBalancer lb, int gauss_number, int exp_number)
	{
		System.out.print(source_1);
		System.out.print("\t");
		System.out.print("Push ("+ gauss_number +")");
		System.out.print("\t");
		System.out.print(lb);
		System.out.print("\t");
		System.out.println("Pull ("+ exp_number +")");
		System.out.println("Servers:");
		
		for (Server sv : lb.getServerList()) {
			System.out.println(sv);
		}
	}
	
}
